#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "fdtd_2d.h"

void init_array(
    int tmax,
    int nx,
    int ny,
    double ex[20][30],
    double ey[20][30],
    double hz[20][30],
    double _fict_[20]) {
    int i, j;

    for (i = 0; i < tmax; i++)
        _fict_[i] = (double)i;
    for (i = 0; i < nx; i++)
        for (j = 0; j < ny; j++) {
            ex[i][j] = ((double)i * (j + 1)) / nx;
            ey[i][j] = ((double)i * (j + 2)) / ny;
            hz[i][j] = ((double)i * (j + 3)) / nx;
        }
}

void print_array(
    int nx,
    int ny,
    double ex[20][30],
    double ey[20][30],
    double hz[20][30]) {
    int i, j;

    fprintf(stderr, "==BEGIN DUMP_ARRAYS==\n");
    fprintf(stderr, "begin dump: %s", "ex");
    for (i = 0; i < nx; i++)
        for (j = 0; j < ny; j++) {
            if ((i * nx + j) % 20 == 0)
                fprintf(stderr, "\n");
            fprintf(stderr, "%0.6lf ", ex[i][j]);
        }
    fprintf(stderr, "\nend   dump: %s\n", "ex");
    fprintf(stderr, "==END   DUMP_ARRAYS==\n");

    fprintf(stderr, "begin dump: %s", "ey");
    for (i = 0; i < nx; i++)
        for (j = 0; j < ny; j++) {
            if ((i * nx + j) % 20 == 0)
                fprintf(stderr, "\n");
            fprintf(stderr, "%0.6lf ", ey[i][j]);
        }
    fprintf(stderr, "\nend   dump: %s\n", "ey");

    fprintf(stderr, "begin dump: %s", "hz");
    for (i = 0; i < nx; i++)
        for (j = 0; j < ny; j++) {
            if ((i * nx + j) % 20 == 0)
                fprintf(stderr, "\n");
            fprintf(stderr, "%0.6lf ", hz[i][j]);
        }
    fprintf(stderr, "\nend   dump: %s\n", "hz");
}

int main() {
    int tmax = 20;
    int nx = 20;
    int ny = 30;
    int has_errors = 0;

    double ex[20][30];
    double ey[20][30];
    double hz[20][30];
    double _fict_[20];

    char data_buf[256];
    char check_buf[256];

    init_array(tmax, nx, ny, ex, ey, hz, _fict_);

    kernel_fdtd_2d(ex, ey, hz, _fict_);

    FILE *tb_file = fopen("check.data", "r");
    assert(tb_file != NULL && "Couldn't open check data file");

    for (int i = 0; i < nx; i++) {
        for (int j = 0; j < ny; j++) {
            sprintf(data_buf, "%0.6lf", ex[i][j]);
            int res = fscanf(tb_file, "%s", check_buf);
            assert(res == 1 && "read check data file failed");
            if (strcmp(data_buf, check_buf)) {
                printf("ex[%d][%d] = %s, expected_ex[%d][%d] = %s\n",
                       i, j,
                       data_buf,
                       i, j,
                       check_buf);
                has_errors++;
            }
        }
    }
    for (int i = 0; i < nx; i++) {
        for (int j = 0; j < ny; j++) {
            sprintf(data_buf, "%0.6lf", ey[i][j]);
            int res = fscanf(tb_file, "%s", check_buf);
            assert(res == 1 && "read check data file failed");
            if (strcmp(data_buf, check_buf)) {
                printf("ey[%d][%d] = %s, expected_ey[%d][%d] = %s\n",
                       i, j,
                       data_buf,
                       i, j,
                       check_buf);
                has_errors++;
            }
        }
    }
    for (int i = 0; i < nx; i++) {
        for (int j = 0; j < ny; j++) {
            sprintf(data_buf, "%0.6lf", hz[i][j]);
            int res = fscanf(tb_file, "%s", check_buf);
            assert(res == 1 && "read check data file failed");
            if (strcmp(data_buf, check_buf)) {
                printf("hz[%d][%d] = %s, expected_hz[%d][%d] = %s\n",
                       i, j,
                       data_buf,
                       i, j,
                       check_buf);
                has_errors++;
            }
        }
    }

    fclose(tb_file);

    if (has_errors) {
        fprintf(stderr, "Benchmark results are incorrect\n");
        return -1;
    }

    printf("Success.\n");
    return 0;
}
